package Salesman.gui;

import Salesman.City;
import Salesman.Data.DataProvider;
import Salesman.Data.Icons.ImageIcon;
import Salesman.Distances;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.jdesktop.swingx.JXLabel;
import org.jdesktop.swingx.JXMapViewer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.painter.MattePainter;
import org.jdesktop.swingx.painter.Painter;
import org.rlpw.swing.JGroupPanel;
import org.rlpw.swing.JOTable;
import org.rlpw.swing.SelectModel;

public class CityPanel extends JPanel {

    private CityMap mapKit = new CityMap();
    private JOTable<City> table;
    private JButton addButton = new JButton("Hinzufügen", new ImageIcon("list_add.png"));
    private JButton removeButton = new JButton("Entfernen", new ImageIcon("list_remove.png"));

    public CityPanel() {
        setLayout(new BorderLayout());
        table = new JOTable<City>(City.class, DataProvider.getCityData());
        table.getSelectModel().setMode(SelectModel.SINGLE);
        JToolBar bar = new JToolBar();



        addButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (showDialog() == JOptionPane.OK_OPTION) {
                    addCity(new City("Neue Stadt", "S", mapKit.getPos().getLatitude(), mapKit.getPos().getLongitude(), true));
                }
            }
        });

        removeButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                if (DataProvider.getCityData().size() < 5) {
                    JOptionPane.showMessageDialog(null, "Kann nicht gelöscht werden, da nicht ausreichend Städte in der Tabelle verbleiben", "Zu wenig Städte", JOptionPane.WARNING_MESSAGE);
                    return;
                }



                int n = JOptionPane.showConfirmDialog(
                        null,
                        "Möchtest Du wirklich die ausgewählte Stadt entfernen?",
                        "Stadt entfernen?",
                        JOptionPane.YES_NO_OPTION);
                if (n == JOptionPane.YES_OPTION && table.getSelectModel().countSelected() > 0) {
                    removeCity(table.getSelectModel().getSelected().get(0));
                }

            }
        });

        bar.add(addButton);
        bar.add(removeButton);

        checkEnabled();

        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                checkEnabled();
            }
        });

        DataProvider.getCityData().addListDataListener(new ListDataListener() {

            @Override
            public void intervalAdded(ListDataEvent e) {
                checkEnabled();
            }

            @Override
            public void intervalRemoved(ListDataEvent e) {
                checkEnabled();
            }

            @Override
            public void contentsChanged(ListDataEvent e) {
                checkEnabled();
            }
        });

        add("North", bar);
        add("Center", new JScrollPane(table));

    }

    private void checkEnabled() {
        removeButton.setEnabled(table.getSelectModel().countSelected() > 0);
    }

    private int showDialog() {

        JGroupPanel panel = new JGroupPanel(1, 2);
        JXLabel label = new JXLabel("Aus der ausgewählten Position wird "
                + "die Luftlinie ermittelt und multipliziert mit dem Faktor 1.2 in die Matrix eingefügt.");

        label.setVerticalTextPosition(SwingConstants.TOP);
        label.setLineWrap(true);
        label.setPaintBorderInsets(false);
        label.setBackgroundPainter(new MattePainter(new Color(241, 241, 188), true));
        label.setMaxLineSpan(400);
        panel.setComponent(0, 0, mapKit);
        panel.setComponent(0, 1, label);

        JOptionPane pane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);

        JDialog dialog = pane.createDialog("Stadtposition auswählen");
        dialog.setSize(500, 550);
        pane.selectInitialValue();
        dialog.setIconImage(new ImageIcon("map.png").getImage());
        dialog.setVisible(true);
        dialog.dispose();
        Object selectedValue = pane.getValue();

        if (selectedValue == null) {
            return JOptionPane.CLOSED_OPTION;
        }

        if (selectedValue.equals(JOptionPane.OK_OPTION)) {
            return JOptionPane.OK_OPTION;
        }

        return JOptionPane.CLOSED_OPTION;

    }

    private void addCity(City city) {
        double[][] m = DataProvider.getDistances().data();
        double[][] aad = new double[m.length + 1][m.length + 1];
        for (int i = 0; i < m.length; i++) {
            System.arraycopy(m[i], 0, aad[i], 0, m.length);
        }

        for (int i = 0; i < m.length; i++) {
            double d = distance(DataProvider.getCityData().get(i).getxPos(), DataProvider.getCityData().get(i).getyPos(),
                    mapKit.getPos().getLatitude(), mapKit.getPos().getLongitude());

            d = Math.round(d * 1.2);
            aad[m.length][i] = d;
            aad[i][m.length] = d;
        }
        aad[m.length][m.length] = Double.POSITIVE_INFINITY;
        DataProvider.getCityData().add(city);
        DataProvider.setDistances(new Distances(aad));

    }

    private void removeCity(City city) {

        int index = DataProvider.getCityData().indexOf(city);
        double[][] m = DataProvider.getDistances().data();
        double[][] aad = new double[m.length - 1][m.length - 1];
        int addi = 0;
        for (int i = 0; i < m.length; i++) {
            if (i != index) {
                int addj = 0;
                for (int j = 0; j < m.length; j++) {
                    if (j != index) {
                        aad[i + addi][j + addj] = m[i][j];
                    } else {
                        addj = -1;
                    }
                }
            } else {
                addi = -1;
            }
        }
        DataProvider.getCityData().remove(city);
        DataProvider.setDistances(new Distances(aad));

    }

    private double distance(double lat1, double lon1, double lat2, double lon2) {

        double dLat1InRad = lat1 * (Math.PI / 180);
        double dLong1InRad = lon1 * (Math.PI / 180);
        double dLat2InRad = lat2 * (Math.PI / 180);
        double dLong2InRad = lon2 * (Math.PI / 180);
        double dLongitude = dLong2InRad - dLong1InRad;
        double dLatitude = dLat2InRad - dLat1InRad;
        double a = Math.pow(Math.sin(dLatitude / 2), 2) + Math.cos(dLat1InRad) * Math.cos(dLat2InRad) * Math.pow(Math.sin(dLongitude / 2), 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double kEarthRadiusKms = 6376.6;
        return kEarthRadiusKms * c;
    }

    class CityMap extends MapKit {

        private GeoPosition pos = new GeoPosition(51.149147958841425, 14.998612403869629);
        private Image flag = new ImageIcon("flag_blue.png").getImage();

        public CityMap() {

            setAddressLocation(pos);

            getMainMap().addMouseListener(new MouseListener() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    pos = getMainMap().convertPointToGeoPosition(e.getPoint());
                    repaint();
                }

                @Override
                public void mousePressed(MouseEvent e) {
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    getMainMap().setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                }

                @Override
                public void mouseExited(MouseEvent e) {
                }
            });

            getMainMap().setOverlayPainter(new Painter<JXMapViewer>() {

                @Override
                public void paint(Graphics2D g, JXMapViewer t, int i, int i1) {
                    g = (Graphics2D) g.create();

                    Rectangle rect = getMainMap().getViewportBounds();
                    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g.translate(-rect.x, -rect.y);
                    if (pos != null) {
                        Point2D p = getMainMap().getTileFactory().geoToPixel(pos, getMainMap().getZoom());
                        g.drawImage(flag, (int) p.getX() - 3, (int) p.getY() - 20, null);
                    }
                    g.dispose();

                }
            });

            getMainMap().setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
        }

        public GeoPosition getPos() {
            return pos;
        }
    }
}
